#ifndef GLOBAL_VARS_HPP
#define GLOBAL_VARS_HPP

#include <arduino.h>
#include "../TempControl/temperatureControllers.hpp"

struct GlobalVars
{
	static void init();
	static void restartCurves();

	static char outputBuffer[];
	static char inputBuffer[];

	const static int trigRecNum = 256;
	static uint32_t fan0Trigs[trigRecNum], fan1Trigs[trigRecNum], fan2Trigs[trigRecNum];
	static int fan0TrigsIdx, fan1TrigsIdx, fan2TrigsIdx;

	struct PointTemperature
	{
		float readingVal = 0;
		// simulated time rate considered
		unsigned long readingTimeMs = 0;
		float targetVal = 37;
		float limitTargetVal = 0;
		float warningThreshold = 35;

		// proportional to difference between this temp and the source
		// but the plate is different that its about change rate (hard to explain here)
		float affectedBySourceRate = 0.1;
		float convergeToSurroundingRate = 0.1;
		bool affectedBySourceAbsolute = false;

		PointTemperature();
		void setSimuThermalModel(float affectedBySourceRateIn, float convergeToSurroundingRateIn, bool sourceRateAbsolute = false);
		void setSimuRandom(float initial, float target);
		// relativeConvergeToSurroundingRate:: boosted by fan to above 1
		void simuRead(float sourceTempOrChangeRate, float surroundingTemp, float relativeConvergeToSurroundingRate = 1, bool flagVerbose = false);
		void extrasimuRead(float* sourceTempA, float* sourceTempB);
		bool reachedWarningThresh();
		bool nearWarningThresh();
		bool nearWarningThresh(float reading);
	};

	static String identifier;

	static struct C_Temps {

	}Temperature;

	static uint8_t tempState;
	// the heat plate or the sample heating block
	static PointTemperature plateTemp;
	// left when viewed downwards
	static PointTemperature sampleLeftTemp;
	// right when viewed downwards
	static PointTemperature sampleRightTemp;
	// the other side of the heat-pump
	static PointTemperature pumpTemp;
	// optional. measured inside the container
	static PointTemperature containerTemp;
	// optional. measured in the surrounding
	static PointTemperature surroundingTemp;
	// driver module
	static PointTemperature coreTemp;

	static uint8_t heatUpDrivePercent;
	static uint8_t coolDownDrivePercent;
	static uint8_t fanDrivePercent;
	static uint8_t drivesDisable;

	static float temptarget;
	static float mean_Reading;
	static TemperatureControlPlan ctrlPlan;
	static float PIDoutputP;
	static float PIDoutputI;
	static float PIDoutputD;

	static unsigned long timeMs;
	static float speed;
	static float changetarget;
	// >=1: enable simulated data at time elapse rate
	static int flagSimuRate;
	// report everything
	static int flagAutoReportInterval;
	// print simple temperature/output
	static int flagAutoReportCurve;
	static char flagAutoPrintSingle;
	static int flagVerboseMode;
	// even when container temp is available, use just heat bed
	static int flagSampleObMode;

	static int fanSpeedRPSs[3];

	static const char* controlMode2char(int ctrlOn, int ctrlMode);

	// dynamically chosen implementation
	static TemperatureController* heatUpCurve;
	static TemperatureController* heatHoldCurve;
	static TemperatureController* coolDownCurve;
	static TemperatureController* coolHoldCurve;

	static ThermalModel thermalModel;
	static MainTempRecord mainTempRecord;

	struct OnBoot {
		// 0 means neutral, 1 means heat, -1 means cool
		static int controlMode;
		static float tempTarget;
		static int verbose;
	};

	struct MiscFlags {
		static int stopOnCoreOverheat;
		static int heartBeatInterval;
		// 0 if never expire
		static unsigned long heartBeatExpire;
	};

	static void heartBeatUpdate();
	static bool heartBeatCheck();
};

#endif